home *** CD-ROM | disk | FTP | other *** search
/ Freelog 22 / freelog 22.iso / Prog / Djgpp / GPC2952B.ZIP / doc / gpc / demos / absdemo.pas next >
Encoding:
Pascal/Delphi Source File  |  2001-02-08  |  5.6 KB  |  131 lines

  1. {
  2. GPC demo program for the portable use of `absolute' declarations and
  3. how to take care of type sizes and endianness in portable programs.
  4.  
  5. Copyright (C) 1999-2001 Free Software Foundation, Inc.
  6.  
  7. Author: Frank Heckenbach <frank@pascal.gnu.de>
  8.  
  9. This program is free software; you can redistribute it and/or
  10. modify it under the terms of the GNU General Public License as
  11. published by the Free Software Foundation, version 2.
  12.  
  13. This program is distributed in the hope that it will be useful,
  14. but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. GNU General Public License for more details.
  17.  
  18. You should have received a copy of the GNU General Public License
  19. along with this program; see the file COPYING. If not, write to
  20. the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  21. Boston, MA 02111-1307, USA.
  22.  
  23. As a special exception, if you incorporate even large parts of the
  24. code of this demo program into another program with substantially
  25. different functionality, this does not cause the other program to
  26. be covered by the GNU General Public License. This exception does
  27. not however invalidate any other reasons why it might be covered
  28. by the GNU General Public License.
  29. }
  30.  
  31. program AbsoluteDemo;
  32.  
  33. { This is an actual example taken from GPC's CRT unit. Under normal
  34.   circumstances, tricks like the following are *not* necessary.
  35.   They're only meant for special situations that can't be solved
  36.   otherwise.
  37.  
  38.   The situation here is the following: The writers of BP's CRT unit
  39.   had the "brilliant" idea to stuff two values into one variable
  40.   (the minimum x and y coordinates of the current window into
  41.   WindMin and similarly the maximum coordinates into WindMax).
  42.   The x coordinates reside in the lower 8 bits, and the y
  43.   coordinates in the higher 8 bits of the `Word' variables which are
  44.   16 bit in BP. (They apparently thought this was necessary for
  45.   their assembler code to be more efficient which is actually not
  46.   true, but that's another story...)
  47.  
  48.   Their recommended way to access the coordinates is to use bit
  49.   manipulation like `shl', `shr', `and' and `or' (or, mostly
  50.   equivalently, `*', `div' and `mod' by powers of 2). But, of
  51.   course, that's not very comfortable for a language like Pascal.
  52.  
  53.   So we want to make the access easier by using fields of a record,
  54.   without losing compatibility to the thoughtless BP interface.
  55.  
  56.   The way to do it is an `absolute' declaration to create record
  57.   aliases for the `Word' variables. `absolute' declarations are
  58.   supported by the GNU Pascal compiler, so far so good. However, in
  59.   order to remain portable, there are two things to take care of:
  60.   type sizes and endianness.
  61.  
  62.   Type sizes: as always when programming portably, one must not
  63.   assume anything about type sizes except when explicitly requested.
  64.   In particular, we must not assume that a `Word' is 16 bits (and in
  65.   fact, it's usually bigger in GPC). Therefore, there might be
  66.   unused bits in the `Word' variables which we cover with (dummy)
  67.   `Fill' fields in the records. For the (interesting) `X' and `Y'
  68.   fields, we want exactly 8 bits, so we use `Word (8)' (and not
  69.   `Byte', which is usually 8 bits, but not guaranteed to be). To
  70.   compute the size of the `Fill' field in bits, we can then simply
  71.   subtract 16 (the size of the `X' and `Y' fields) from the size of
  72.   `Word' in bits which the `BitSizeOf' function tells us. But
  73.   because we're really paranoid ;-), we add a (compile time) check
  74.   to ensure that the size of our record is really the same as that
  75.   of the `Word' variables. Compile time assertions are not directly
  76.   supported by the compiler, but can be emulated with a little
  77.   trick, see below.
  78.  
  79.   Endianness: on a little-endian system (e.g. x86, Alpha), the lower
  80.   valued parts of an integer variable come first in memory, but on a
  81.   big-endian system (e.g. m68k, Sparc), the higher valued parts come
  82.   first. We must take this into account in the order of the fields
  83.   in our record. GPC gives us the define `__BYTES_LITTLE_ENDIAN__'
  84.   or `__BYTES_BIG_ENDIAN__' in order to distinguish little- and
  85.   big-endian systems.
  86.  
  87.   And last, but not least, of course, we must not forget to use a
  88.   `packed' record, so the fields are really packed end to end. }
  89.  
  90. { First of all, these are the `Word' variables we want to alias. }
  91. var
  92.   WindMin : Word;
  93.   WindMax : Word;
  94.  
  95. { Now our record type, taking into account type sizes and endianness. }
  96. type
  97.   TWindowXY = packed record
  98.     {$ifdef __BYTES_BIG_ENDIAN__}
  99.     Fill : Integer (BitSizeOf (Word) - 16);
  100.     Y, X : Word (8)
  101.     {$else}
  102.     X, Y : Word (8);
  103.     Fill : Integer (BitSizeOf (Word) - 16)
  104.     {$endif}
  105.   end;
  106.  
  107. { Make sure TWindowXY really has the same size as WindMin and
  108.   WindMax. If not, compilation will abort here with `division by
  109.   zero'. Otherwise, the value of the constant will always be 1, and
  110.   is of no further interest. }
  111. const
  112.   AssertTWindowXYSize = 1 / Ord ((SizeOf (TWindowXY) = SizeOf (WindMin)) and
  113.                                  (SizeOf (TWindowXY) = SizeOf (WindMax)));
  114.  
  115. { And now the aliased record variables via `absolute' declarations. }
  116. var
  117.   WindowMin : TWindowXY absolute WindMin;
  118.   WindowMax : TWindowXY absolute WindMax;
  119.  
  120. begin
  121.   Writeln ('Setting the minimum coordinates (2, 4) the "dirty" way.');
  122.   WindMin := 2 + $100 * 4;
  123.   Writeln ('Reading them back the easy way: (', WindowMin.X, ', ', WindowMin.Y, ').');
  124.   Writeln;
  125.   Writeln ('And vice versa...');
  126.   Writeln ('Setting the maximum coordinates to (42, 24) the easy way.');
  127.   WindowMax.X := 42;
  128.   WindowMax.Y := 24;
  129.   Writeln ('Reading them back the "dirty" way: (', WindMax mod $100, ', ', WindMax div $100, ').')
  130. end.
  131.